<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!-- 视图(view)  页面,用于做html展示 -->
    <div id="app">
        <p></p>
        <p></p>
        <p></p>
    </div>
</body>
<script>
    // 模型(model)  数据层, 用于存放视图展示所依赖的数据 (整合到一起)
    let data = {
        msg: "hello world",
        count: 100,
        list: [1, 2, 3, 4, 5],
        info: {
            name: "张三",
            age: 18,
        }
    }

    // DOM操作 (模拟Vue -> !!!!简易版)
    // 1. 页面加载时 默认渲染一次
    // 2. 监听数据改变, 数据改变之后再次更新视图

    /* 
        当前案例缺点:
        1.  只要有一个数据改变, 整个视图全部更新 (!!最好更新部分)
        2.  如果监听的属性的属性值是一个引用类型(数组和对象), 修改该数组和对象无法检测到
            简单来说: 只关注对象data根属性的属性值是否改变, 如果属性值是一个引用类型(数组和对象),修改该数组和对象,该属性对应的值没有改变 (!!! data的属性值是数组和对象  二次处理)
    
        上述缺点Vue已经解决!!!
            1. 虚拟dom和diff算法
            2. 深度劫持
    */


    for (let key in data) {
        console.log(key);
        let _default = data[key]; // 中间变量 提前存储key的值

        Object.defineProperty(data, key, {
            enumerable: true,
            configurable: true,
            get: function () { // 对某个属性取值时执行对应的回调函数 => 回调函数的返回值就是获取的值
                console.log("取值拦截", key);
                return _default;
            },
            set: function (newVal) {// 对某个属性赋值时执行对应的回调函数(回调函数有一个形参,接收新值)
                console.log("赋值拦截", key, newVal);
                _default = newVal;

            }
        })

        if(Object.prototype.toString.call(_default) === "[object Object]"){
            for (let key in _default) {
                console.log(key);
                let _def = data[key]; // 中间变量 提前存储key的值

                Object.defineProperty(data, key, {
                    enumerable: true,
                    configurable: true,
                    get: function () { // 对某个属性取值时执行对应的回调函数 => 回调函数的返回值就是获取的值
                        console.log("取值拦截", key);
                        return _def;
                    },
                    set: function (newVal) {// 对某个属性赋值时执行对应的回调函数(回调函数有一个形参,接收新值)
                        console.log("赋值拦截", key, newVal);
                        _def = newVal;

                    }
                })

                if(Object.prototype.toString.call(_default) === "[object Object]"){
                    
                }
            }
        }
    }

    console.log(data);

    // data.msg = "hello vue!!!";
    // data.count ++;

    // data.list = [4, 3, 2, 1];    // 新值覆盖旧值  => 可以被检测到
    // data.list.push("a");   // 直接给原数组新值元素, 
   
    // data.info = {name:"李四",age:22};    // 新值覆盖旧值  => 可以被检测到
    // data.info.name = "李四";       // 直接给原对象的属性修改数值, 


    /* 
        Vue2的响应式本质依赖于Object.defineProperty(),对应data中挂载数据的键名绑定取值拦截和赋值拦截
        1. 如果直接对应属性名赋新值,可以被Vue响应式机制检测到
        2. 如果data属性的属性值是数组和对象, 直接修改数组和对象中数据, 不可以被Vue响应式机制检测到
    
    */










</script>


</html>